#pragma once
#include "log.hpp"
#include "ThreadPool.hpp"
#include "Task.hpp"

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <signal.h>
#include <thread>

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#include <sys/wait.h>


#include "deamon.hpp"

using namespace std;
Log log;
const int deafault_fd = -1;
const string deafault_ip = "0.0.0.0";
const int backlog = 5; // 一般不要设置过大 < 10;

enum{
    USAGE_ERR = 1,
    SOCK_CREAT_ERR,
    BIND_ERR,
    LISTEN_ERR
};
class TcpServer;//向前神明
class ThreadData
{
public:
    ThreadData(const uint16_t& port, const string& ip, TcpServer* t)
        :sockfd_(0)
        ,clientport_(port)
        ,clientip_(ip)
        ,tsvr_(t)
    {}
public:
    int sockfd_;
    string clientip_;
    uint16_t clientport_;
    TcpServer* tsvr_;
};
class TcpServer
{
public:
    TcpServer(const uint16_t& port, const string& ip = deafault_ip)
        :listensockfd_(deafault_fd)
        ,port_(port)
        ,ip_(ip)
    {}


    void InitServer()
    {
        listensockfd_ = socket(AF_INET, SOCK_STREAM, 0);//ipv4 、面向字节流、协议类型0
        if(listensockfd_ < 0)
        {
            log(Fatal, "create listensockfd_ error: %d, errstring: %s", errno, strerror(errno));
            exit(SOCK_CREAT_ERR);
        }
        log(Info, "create listensockfd_ success, listensockfd_ is: %d", listensockfd_);

        //初始化套接字信息
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(port_);//? 主机序列号转，统一大小端问题
        inet_aton(ip_.c_str(), &local.sin_addr);//string 转 4字节

        //local.sin_addr.s_addr = INADDR_ANY;

        if(bind(listensockfd_, (const struct sockaddr*)&local, sizeof(local)) < 0)
        {
            log(Fatal, "bind err, errno: %d, errstring: %s",errno, strerror(errno));
            exit(BIND_ERR);
        }
        log(Info, "bind listensockfd_ success");

////////////////////////////以下区别UDP套接字///////////////////////////////////////////
        //1.TCP设置套接字为【监听状态】
        if(listen(listensockfd_, backlog) < 0)
        {
            log(Fatal, "listen err, error: %d, errstring: %s", errno, strerror(errno));
            exit(LISTEN_ERR);
        }
        log(Info, "listen listensockfd_ success");

    }
    // static void* Routine(void* args)
    // {
    //     pthread_detach(pthread_self());//将自己处为分离状态

    //     ThreadData* td = static_cast<ThreadData*>(args);
    //     td->tsvr_->Service(td->sockfd_, td->clientport_, td->clientip_);
    //     delete td;
    //     return nullptr;
    // }
    void RunServer()
    {
        //daemon();
        ThreadPool<Task>::GetInstance()->Start();//启动线程池
        //signal(SIGCHLD, SIG_IGN);//忽略子进程信号
        while(true)
        {
            log(Info, "TCP_Server is running....");
            sleep(1);

            //1. 获取新连接
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            int sockfd = accept(listensockfd_, (sockaddr*)&client, &len);//0 触发阻塞等待
            if(sockfd < 0)
            {
                //并不能因为一个连接获取失败就终止进程
                log(Warning, "accept error, error: %d, errstring: %s", errno, strerror(errno));
                continue;
            }

            uint16_t clientport = ntohs(client.sin_port);
            char ipstr[32];
            inet_ntop(AF_INET, &(client.sin_addr), ipstr, sizeof(ipstr));//防止了inet_ntoa的数据不一致问题

            //2. 根据新连接进行通信
            log(Info, "get a new link! sockfd is: %d\n, client ip: %s, client port: %d", sockfd, ipstr, clientport);

            //开始提供服务：version 1 单进程
            // Service(sockfd, clientport, ipstr);
            // close(sockfd);

            //vision 2 多进程
            // pid_t id = fork();
            // if(id == 0)
            // {
            //     close(listensockfd_);//must
            //     if(fork() > 0) exit(0);//非阻塞技巧——这里创建出孙子进程并且条件满足直接退出子进程
            //     //1. 孙子进程不用等待，只需要管自己的子进程就行，【托孤给系统，自动回收】
            //     //2. 实现了非阻塞
            //     //子进程
            //     Service(sockfd, clientport, ipstr);//孙子进程
            //     close(sockfd);
            //     exit(0);
            // }
            // //父进程
            // close(sockfd);//must
            // pid_t rid = waitpid(id, nullptr, 0);
            // (void)rid;
            
            //version 3 多线程
            // ThreadData* td = new ThreadData(clientport, ipstr, this);
            // pthread_t tid;
            // pthread_create(&tid, nullptr, Routine, td);

            //version 4 线程池
            Task t(sockfd, ipstr, clientport);
            ThreadPool<Task>::GetInstance()->Push(t);
        }
    }
    // void Service(const uint16_t sockfd, const uint16_t& clientport, const string& ipstr)
    // {
    //     //echo server
    //     char buffer[4096];
    //     while(true)
    //     {
    //         //先使用sockfd描述符读取文件内容，就可以根据用户请求做出相应动作了
    //         //TCP面向字节流
    //         ssize_t n = read(sockfd, buffer, sizeof(buffer));
    //         if(n > 0)
    //         {
    //             buffer[n] = 0;
    //             cout << "client say@ " << buffer << endl;
    //             string echo_string = "TCP_Server echo# ";
    //             echo_string += buffer;

    //             write(sockfd, echo_string.c_str(), strlen(echo_string.c_str()));//写回数据流
    //         }
    //         else if(n == 0)
    //         {
    //             log(Info, "Client quit, server close fd: %d", sockfd);
    //             break;
    //         }else
    //         {
    //             log(Warning, "read error, error: %d, errstring: %s", errno, strerror(errno));
    //             break;
    //         }

    //     }
    // }

    ~TcpServer()
    {}
private:
    int listensockfd_;
    uint16_t port_;
    string ip_;
};